package com.kunyi.web.im.websocket.handler;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.kunyi.web.im.websocket.TransportService;
import com.kunyi.web.im.websocket.entity.DataEntity;
import com.kunyi.web.im.websocket.entity.SocketCommand;
import com.kunyi.web.im.websocket.entity.instantMessagingEntity;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentMap;

/**
 * @ClassName TextWebSocketFrameHandler  WebSocket文本帧处理
 * @Description 这里的TextWebSocketFrame表示的就是一个文本帧（Frame）
 * @Author zhenguo.zhuang
 * @Date 2024/03/29
 * @Version 1.0
 **/
@Slf4j
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{

    /**
     * 客户端订阅了的消息 String为订阅的消息主题字符串
     */
    public List<String> subscribeTopicList = new ArrayList<>();
    /**
     * 当前ctx处理类
     */
    private ChannelHandlerContext ctx;
    /**
     * 管理通道，以及向客户端发送消息类
     */
    TransportService service;
    /**
     * 客户端id
     */
    private String uuid ;

    /**
     * @author: zhenguo.zhuang
     * @Description 客户端连接id
     * @Date 15:53 2024/4/1
     * @Param userId:
     * @return null
     **/
    public TextWebSocketFrameHandler(String userId) {
            if (StrUtil.isEmpty(userId)){
                userId="admin";
            }
            service=SpringUtil.getBean(TransportService.class);
            this.uuid= IdUtil.simpleUUID()+"_"+userId;
    }
    /**
     * @author: zhenguo.zhuang
     * @Description 处理用户触发事件
     * @Date 16:12 2024/3/29
     * @Param ctx:
	 * @Param evt:
     * @return void
     **/
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        //Websocket协议在握手时是通过HTTP(S)协议进行的，那么这个WebSocketHandshakeHandler应该就是处理HTTP相关的数据
        //如果握手完成，说明有一个客户端连接了
        if( evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE){
            //回复客户端消息
//            ctx.writeAndFlush(new TextWebSocketFrame("success"));
            //在session中保存当前会话
            this.ctx=ctx;
            service.registerSessions(uuid, this);
            //保存此客戶端的channel
            log.info("客户端上线{}",uuid);
        //如果超过规定时间，没有收到任何消息，则注销这个通道
        }else if(evt instanceof IdleStateEvent){
            log.error("长时间未收到客户端的消息{}",uuid);
            //如果需要心跳检测机制，则打开此选项
            //service.deregisterSession(uuid);
            //ctx.channel().close();
        }else {
            super.userEventTriggered(ctx, evt);
        }
    }
    /**
     * @author: zhenguo.zhuang
     * @Description 客户端连接后，触发
     * @Date 15:11 2024/3/29
     * @Param ctx:
     * @return void
     **/
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        this.ctx=ctx;
        log.info("客户端上线:{}",uuid);
    }
    /**
     * @author: zhenguo.zhuang
     * @Description 客户端下线后触发
     * @Date 15:13 2024/3/29
     * @Param ctx:
     * @return void
     **/
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端下线:{}",uuid);
        service.deregisterSession(uuid);
        super.channelInactive(ctx);
    }
    /**
     * @author: zhenguo.zhuang
     * @Description 处理客户端发送的消息
     * @Date 15:06 2024/3/29
     * @Param ctx: 通道
	 * @Param meg: 消息，文本帧
     * @return void
     **/
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame meg) throws Exception {
        //将文本帧转化为text
        this.ctx = ctx;
        String text = meg.text();
        try {
            DataEntity data = JSONObject.parseObject(text, DataEntity.class);
            if (data.getCommand() == null) {
                return;
            }
            SocketCommand socketCommand = SocketCommand.getSocketCommand(data.getCommand());
            switch (socketCommand) {
                //心跳
                case HEARTBEAT:
                    log.info("收到了客户端:{}, 的心跳信息",uuid);
                    break;
                //订阅消息
                case SUBSCRIBE:
                    processSubscribe(ctx, data);
                    break;
                //取消订阅
                case NO_SUBSCRIBE:
                    unSubscribe(ctx,data);
                    break;
                //即时通讯
                case INSTANT_MESSAGING:
                    instantMessaging(ctx,data);
                    break;
                default:
                    break;
            }
        }catch (JSONException e){
            log.error(new StringBuilder("收到了格式错误的客户端消息:{").append(text).append("}").toString());
        }catch (Exception e){
            e.printStackTrace();
        }

    }


    /**
     * @author: zhenguo.zhuang
     * @Description 保存客户端订阅的消息
     * @Date 16:02 2024/3/29
     * @Param ctx:
	 * @Param data:
     * @return void
     **/
    public void processSubscribe(ChannelHandlerContext ctx, DataEntity data){
        log.info("收到了客户端{}的订阅消息{}",uuid,data.getContent());
        List<String> newSubList = JSONArray.parseArray(data.getContent()).toJavaList(String.class);
        this.subscribeTopicList.addAll(newSubList);
    }

    /**
     * @author: zhenguo.zhuang
     * @Description 取消订阅
     * @Date 16:02 2024/3/29
     * @Param ctx: 通道
     * @Param data: 接收消息实体
     * @return void
     **/
    public void unSubscribe(ChannelHandlerContext ctx, DataEntity data){
        log.info("收到了客户端{}取消订阅消息{}",uuid,data.getContent());
        List<String> newSubList = JSONArray.parseArray(data.getContent()).toJavaList(String.class);
        this.subscribeTopicList.removeAll(newSubList);
    }


    /**
     * @author: zhenguo.zhuang
     * @Description
     * @Date 16:04 2024/4/1
     * @Param ctx: 通道
     * @Param data: 接收消息实体
     * @return null
     **/
    public void instantMessaging(ChannelHandlerContext ctx,DataEntity data){
        String content = data.getContent();
        instantMessagingEntity instantMessagingEntity = JSONObject.parseObject(content, instantMessagingEntity.class);
        //得到所有的客户端连接
        ConcurrentMap<String, TextWebSocketFrameHandler> session = service.getSession();
        //需要发送的用户idList
        List<String> userIdList = instantMessagingEntity.getUserIdList();
        String message = instantMessagingEntity.getMessage();
        //当前用户id
        String user = uuid.substring(uuid.lastIndexOf("_")+1);
        //遍历找到这些客户端，向这些客户端发送信息
        session.forEach((uuid, handler) -> {
            String userId = uuid.substring(uuid.lastIndexOf("_")+1);
            if(userId.contains("@")){
                userId = userId.substring(uuid.lastIndexOf("@")+1);
            }
            String finalUserId = userId;
            Optional<String> first = userIdList.stream().filter(item -> item.equals(finalUserId)).findFirst();
            if (first.isPresent()){
                log.info("向客户端{}发送的消息{}",user,message);
                handler.sendMsg(user+":"+message);
            }
        });
    }



    /**
     * @author: zhenguo.zhuang
     * @Description 服务端向客户端发送消息
     * @Date 16:38 2024/3/29
     * @Param msg: 消息内容
     * @return void
     **/
    public void sendMsg(String msg) {
        log.info("发送消息：{}",msg);
        this.ctx.writeAndFlush(new TextWebSocketFrame(msg));
    }

}
